package graph_viewer.structure.builder;

import java.awt.*;
import java.io.*;
import java.util.*;

import graph_viewer.util.*;
import graph_viewer.structure.*;

/**
	this class read data from the .inf file, which format is defined by Paul Wanchun Li
*/// read node data from file stream, and create a generic tree
public class Spring_Graph_Builder extends Basic_Builder{
	public static void main(String arg[])  throws IOException{
		Spring_Graph_Builder tgb	= new Spring_Graph_Builder( "28_5.spr" );

		Tree	tree	= new Generic_Tree();
		//Tree	created_tree	= tgb.build_tree( tree );

//		Structure_Util.traverse_tree( created_tree );

		Graph	cg	 = tgb.build_clustered_graph(tree);

		ArrayList edges	= cg.find_edges();

		for ( Iterator _i = edges.iterator(); _i.hasNext(); ){
			String[] edge = (String[])_i.next();
			Debug.println( "\tstart " + edge[0] + ", end " + edge[1], 3 );
			
			//ArrayList edge	= (ArrayList)_i.next();
			//Object edge	= _i.next();
			//Debug.println( "\t" + edge.getClass().getName() + edge, 2 );
			//String 
			//	start	= (String)edge.get(0),
			//	end	= (String)edge.get(1);

			//Debug.println( "\t" + start + ", " + end, 2 );
			
		}

	}	

	private File	node_data;

	//============================================================================
	// constructor
	//============================================================================	
	public Spring_Graph_Builder( String a_file_name ) throws IOException{
		this( new File(a_file_name) );		
	}

	public Spring_Graph_Builder( File a_file ) throws IOException{
		if ( is_valid_data_file(a_file) ){
			set_file( a_file );
			//Debug.println( " File is NOT null " , 2);
		} else {
			Debug.println( " File is null " , 2);
			node_data	= null;
		}
	}

	//============================================================================
	// setter&getter
	//============================================================================
	public void set_file( File a_file ){
		node_data	= a_file;
	}

	public File get_file(){
		return this.node_data;
	}
	//============================================================================
	// public methods
	//============================================================================
	public Graph build_clustered_graph( Tree cluster_tree ) throws IOException {
		Tree created_cluster_tree	 = build_tree( cluster_tree );

		//set is_closed status
		created_cluster_tree.traverse(
			new Command(){
				public void do_action( Node node ){					
					// all nodes default is_closed == false
					if ( node.is_leaf() ){
						node.set_is_closed( true );
					} 
				}
				
			}
		);

		Clustered_Graph	a_c_g	= new Clustered_Graph( created_cluster_tree );
		ArrayList				edges		= build_edges( a_c_g );
		a_c_g.set_edges( edges );

		return a_c_g;
	}
	
	
	//the first element of collection must be the node
	public Tree build_tree( Tree created_tree ) throws IOException{
		ArrayList	node_information_list	= create_node_information_list();
		
		Debug.println("====================build_tree==================================", 2 );
		for ( Iterator iter = node_information_list.iterator() ; iter.hasNext() ; ){
			ArrayList an_element_node_information_list	= (ArrayList)iter.next();		
			Node	an_node	 = create_tree_node( an_element_node_information_list );
			created_tree.add_node(an_node);
		}		
		//to-do: node position
		Debug.println("===================build_tree end==================================", 2);
		
		return created_tree;
	}

	public ArrayList build_edges( Graph a_graph ) throws IOException{
		ArrayList	 edges	= new ArrayList();
		ArrayList edges_info = create_edges_info();
		
		
		for ( Iterator iter=edges_info.iterator(); iter.hasNext(); ){
			String[] an_edge			= (String[])iter.next();	
			
			Debug.println( "build_edges: " + an_edge[0] + "---" + an_edge[1], 2 );
			edges.add( an_edge );
		}		

		return edges;
	}



	//============================================================================
	// private methods
	//============================================================================


	//@param element are arraylists that contains node, parent
	private Node create_tree_node( ArrayList node_information) throws IOException{
		String 
			node_label	= (String)node_information.get(0),
			parent_label	=  (String)node_information.get(1);
		
		Node	new_node;

		HashMap node_position_map	= create_node_position_map();

		if ( Structure_Util.is_null_label(parent_label) ){
			Debug.println( "node_label:" + node_label, 2 );
			new_node	 = new Node( node_label );
		}else{
			new_node	 = new Node( node_label, new Node( parent_label ) );
			Debug.println( "node_label:" + node_label, 2 );
		}

		Node_Position	np	 =(Node_Position)node_position_map.get( node_label );

		new_node.set_position( np );

		//find position info
		return new_node;
	}
	
	private ArrayList create_node_position() throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );

		ArrayList node_position_list	= new ArrayList();

		while ( true ){
			String node_list_string = node_data_reader.readLine().trim() ;
			
			if ( is_end_flag(node_list_string ) ){
				break;
			}

			if ( node_list_string.startsWith( position ) ){
				ArrayList node_position	= retrive_node_position( node_list_string );
				node_position_list.add( node_position );
			}	
			
		}

		node_data_reader.close();
		
		return node_position_list;	
	}

	//@return  element are arraylists that contains node, parent.
	private ArrayList create_node_information_list() throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );

		ArrayList node_information_list	= new ArrayList();

		while ( true ){
			String node_list_string = node_data_reader.readLine().trim() ;
			
			if ( is_end_flag(node_list_string ) ){
				break;
			}
			
			if ( node_list_string.startsWith( relation ) ){
				ArrayList node_information	= retrive_node_information( node_list_string );
				node_information_list.add( node_information );
			}	
			
		}

		node_data_reader.close();
		
		return node_information_list;	
	}
	
	//@return Map. e.x node_label==node_position
	private HashMap create_node_position_map( )  throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );
		
		HashMap node_position_map	= new HashMap();

		while ( true ){
			String node_list_string = node_data_reader.readLine().trim() ;
			
			if ( is_end_flag(node_list_string ) ){
				break;
			}

			if ( node_list_string.startsWith( position ) ){
				ArrayList node_position = retrive_node_position( node_list_string );
				String node_label		= (String)node_position.get(0);
				Node_Position	np		= (Node_Position)node_position.get(1);

				node_position_map.put( node_label, np );
			}
		}

		return node_position_map;
	}
	
	//@ all the edges of ArrayList, element is String[] { node_labal_start, node_labal_end }
	private ArrayList create_edges_info() throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );

		ArrayList		edges_info				= new ArrayList();

		while ( true ){
			String edge_list_string = node_data_reader.readLine().trim() ;
			
			if ( is_end_flag(edge_list_string ) ){
				break;
			}

			if ( edge_list_string.startsWith( edge ) ){
				//ArrayList edge	= retrive_edge_information( edge_list_string );
				String[] edge	= retrive_edge_information( edge_list_string );
				
				edges_info.add(edge);
			}
	
		}

		node_data_reader.close();

		return edges_info;
	}

	//@param	edge_information_list	a string read out from a file. e.x: !	a1	 b1
	private String[] retrive_edge_information( String edge_infomation_list ){
		ArrayList	edge_list		= new ArrayList();
		
		StringTokenizer st	= new StringTokenizer( edge_infomation_list );
		while ( st.hasMoreTokens() ){
			edge_list.add( st.nextToken() );
		}

		edge_list.remove( 0 );//remove starting flag

		String 
			start_label	= (String)edge_list.get(0),
			end_label	= (String)edge_list.get(1);

		return new String[] {start_label, end_label};
	}

	// @return  String node_label, Node_Position node_position
	private ArrayList retrive_node_position( String node_position_list){
		ArrayList	node_list		= new ArrayList();

		StringTokenizer st	= new StringTokenizer( node_position_list );
		while ( st.hasMoreTokens() ){
			node_list.add( st.nextToken() );
		}
		
		node_list.remove( 0 ); //remove starting flag
		String
			node_label	= (String)node_list.get(0),
			x_center		= (String)node_list.get(1),
			y_center		= (String)node_list.get(2);
		
		Node_Position	np		= new Node_Position( Integer.parseInt(x_center), Integer.parseInt(y_center) );

		ArrayList node_position	= new ArrayList();
		node_position.add( node_label );
		node_position.add(np );

		return node_position;
	
	}

	// @return the arraylist incudling: node label and parent label.
	private ArrayList retrive_node_information( String node_information_string ){
		ArrayList	node_list		= new ArrayList();
		StringTokenizer st	= new StringTokenizer( node_information_string );
		while ( st.hasMoreTokens() ){
			node_list.add( st.nextToken() );
		}

		node_list.remove( 0 );//remove starting flag

		return node_list;
	}

};
